package exteditapp;


import java.util.ArrayList;

import javax.swing.JApplet;

import exteditapp.state.IState;

/**
 * Interface for program modules
 * 
 * Interface for main application module. Is part of MVC specification in this main application.
 * Main program logic is actually putted inside or Module or is being invoked my methods in Module.
 * @author Arturas Smorgun, arturas@smorgun.lt
 * 
 */
public abstract class IModuleApplet extends JApplet implements ISubject {

	/**
	 * Serial number of class
	 */
	private static final long serialVersionUID = -6888652516425042868L;

	/**
	 * URL Suffixes for several actions.
	 */
	public final String URL_CHECK_DATE = "/@@externaleditor_info/checkModificationDate"; //return date of last modification
	public final String URL_CHECK_EDIT = "/@@externaleditor_info/checkEditPermission"; //check file edit permission
	public final String URL_CHECK_LOCK = "/@@externaleditor_info/checkLock"; //check file lock position
	public final String URL_DO_LOCK = "/@@externaleditor_info/doLock"; //do lock of file
	public final String URL_DO_UNLOCK = "/@@externaleditor_info/doUnlock"; //do unlock of file
	
	/**
	 * List of listeners for current subject
	 */
	protected ArrayList<IListener> listeners = new ArrayList<IListener>();
	
	/**
	 * Settings object - holds all settings: both runtime and system
	 */
	protected ISettings settings;
	
	/**
	 * File which user is used to open for external editing
	 */
	protected FileDefault workingFile;
	
	/**
	 * Main controller which controls this module
	 */
	protected IController controller;
	
	/**
	 * Main module iterator
	 */
	protected AppletIterator iterator;
	
	/**
	 * Command invoker
	 */
	protected Invoker invoker = new Invoker();
	
	/**
	 * Return settings
	 * @return current settings object
	 */	
	public ISettings getSettings(){
		return this.settings;
	}	

	/**
	 * Set the value of settings.
	 * @param mysettings Settings object which deals with ALL settings
	 */
	public void setSettings(ISettings mysettings){
		this.settings = mysettings;
	}	

	/**
	 * Return workingFile
	 * @return current working file
	 */	
	public FileDefault getWorkingFile(){
		return this.workingFile;
	}	

	/**
	 * Set the value of workingFile.
	 * @param myworkingFile new working file
	 */
	public void setWorkingFile(FileDefault myworkingFile){
		this.workingFile = myworkingFile;
	}

	/**
	 * Tries to register new listener to current subject. On success returns true and false otherwise
	 * @param listener new listener
	 * @return true on success false otherwise
	 */
	public boolean registerListener(IListener listener){
		if(listeners.contains(listener)){
			return false;
		}
		listeners.add(listener);
		return true;
	}
	
	/**
	 * Tries to unregister existing listener from current subject. On success returns true and false otherwise
	 * @param listener try to unregister listener from list
	 * @return true on removal, false if listener not registered
	 */
	public boolean unregisterListener(IListener listener){
		if(listeners.contains(listener)){
			listeners.remove(listener);
			return true;
		}
		return false;
	}
	
	/**
	 * Ability to access current state of module from outside.
	 * @return current state (this method can be used by unregistered listeners or even other classes)
	 */
	public IState getState() {
		return this.getWorkingFile().getCurrentState();
	}
	
	/**
	 * Returns controller of this module.
	 * @return current module controller.
	 */
	public IController getController(){
		return this.controller;
	}
	
	/**
	 * Sets controller of this module.
	 * @param controller new module controller.
	 * @return true on success and false otherwise.
	 */
	public boolean setController(IController controller){
		this.controller = controller;
		return true;
	}
	
	/**
	 * Returns command invoker
	 * @return
	 */
	public Invoker getInvoker(){
		return this.invoker;
	}
	
	/**
	 * Loads given params (in applet they are from <PARAM>, and in command line they are from parameters after java applet name
	 * @return true on loading and false if no parameters found
	 */
	public boolean getParams(){
		//TODO parameters loading and their default values
		String[] names = {
			"fileName", "",
			"fileCheckInterval", "10",
			"fileEditTimeout", "60",
			"fileAutoSaveInterval", "60",
			"fileModified", "0",
			"fileLocked", "0",
		};
		String tmpString;
		for(int i = 0; i < names.length; i+=2){
			tmpString = getParameter(names[i]);
			if(tmpString == null)
				tmpString = names[i+1];
			settings.setRuntimeParameter(names[i], tmpString);
			System.out.println(names[i]+"\t\t"+tmpString);
		}
		return true;
	}
	
	/**
	 * Check if SecurityManager has the clipboard locked out.
	 * @returns true if it is this program can use the clipboard without getting a SecurtiyException.
	 */
	protected boolean isSafetToUseClipboard(){
		SecurityManager sm = System.getSecurityManager();
		if(sm != null){
			try {
				sm.checkSystemClipboardAccess();
			}
			catch(SecurityException e){
				return false;
			}
		}
		return true;
	}
	
	/**
	 * Notifies all listeners about changed state.
	 */
	public abstract void notifyListeners();
	
	/**
	 * This method is intended for whatever initialization is needed for applet. 
	 * It is called after the param attributes of the applet tag.
	 */
	public void init(){
		start();
	}
	
	/**
	 * This method is automatically called after init method. 
	 * It is also called whenever user returns to the page containing the applet after visiting other pages.
	 */
	public abstract void start();
	
	/**
	 * This method is automatically called whenever the user moves away from the page containing applets.
	 * You can use this method to stop an animation.
	 */
	public abstract void stop();
	
	/**
	 * This method is only called when the browser shuts down normally. 
	 */
	public void destroy(){
		stop();
	}
	
	/**
	 * In this method graphical environment is being made.
	 */
	public abstract void paint();

}
